local state = {}
state.name = "AIMING DIRECT"
state.id = 2

if(SERVER) then

  include("includes/enum/disposition.lua")
  
  state.targetPos = nil
  state.targetEnt = nil
  state.startTime = nil
  state.maxAimingTime = 5
  state.targetingResolution = 50

  function state.New()
    local newState = table.Copy(state)
    
    return newState
  end

  function state:Run(ag3)
    if(self.startTime == nil) then
      self.startTime = CurTime()
    end
    
    local isAimingTimeElapsed = (CurTime() - self.startTime) > self.maxAimingTime
    
    if(isAimingTimeElapsed || ag3:IsArmed() ~= true) then
      return ag3:SetNextState(ag3.States.Idle)
    end
    
    if(ValidEntity(self.targetEnt)) then
      self.targetPos = self.targetEnt:GetPos()
    else
      self.targetPos = ag3:GetTarget()
      
      if(self.targetPos ~= nil) then
        for _, entity in pairs(ents.FindInSphere(self.targetPos, self.targetingResolution)) do
          if(ValidEntity(entity) && entity:IsWorld() == false) then
            self.targetEnt = entity
            break
          end
        end
      else
        return ag3:SetNextState(ag3.States.Idle)
      end
      
      if(ValidEntity(self.targetEnt) && self.targetEnt:IsNPC()) then
        self.targetEnt:AddEntityRelationship(ag3, D_FR, 99)
      end
    end
       
    self:UseAimingPhysics(ag3)
    
    local isAimedAtTarget = nil
    
    if(ValidEntity(self.targetEnt)) then
      isAimedAtTarget = self:IsAimedAtEntity(ag3, self.targetEnt)
    else
      local targetAngle = (self.targetPos - ag3:GetPos()):Angle()
      
      isAimedAtTarget = ag3:GetForward():Distance(targetAngle:Forward()) < 0.01
    end
    
    if(isAimedAtTarget == false) then
      DebugMsg(tostring(ag3) .. " is aiming at " .. tostring(self.targetEnt or self.targetPos) .. ".\n")
    else
      DebugMsg(tostring(ag3) .. " is aimed at " .. tostring(self.targetEnt or self.targetPos) .. ".\n")
    end
    
    if(isAimedAtTarget) then
      return ag3:SetNextState(ag3.States.Charging)
    end
    
    return self
  end
  
  function state:IsAimedAtEntity(ag3, entity)
    local traceSpec = {}
    traceSpec.start = ag3:GetEmitterPos()
    traceSpec.endpos = traceSpec.start + (ag3:GetForward() * ag3:GetRange())
    traceSpec.filter = ag3.Entity
    local trace = util.TraceLine(traceSpec)
    
    DebugMsg(table.ToString(trace, "Aiming trace for " .. tostring(ag3), true))
    
    return ValidEntity(trace.Entity) && trace.Entity == entity
  end
  
  function state:UseAimingPhysics(ag3)
    ag3.PhysicsSimulate = function(entity, physics, timeDelta)
      physics:Wake()
      
      if(self.targetPos == nil) then
        return SIM_NOTHING
      end
      
      local targetVector = self.targetPos - ag3:GetPos()
      
      local shadowParams = {}
      shadowParams.secondstoarrive = 1
      shadowParams.pos = ag3:GetPos()
      shadowParams.angle = targetVector:Angle()
      shadowParams.maxangular = 500
      shadowParams.maxangulardamp = 2000
      shadowParams.maxspeed = 50
      shadowParams.maxspeeddamp = 200
      shadowParams.dampfactor = 0.6
      shadowParams.teleportdistance = 0
      shadowParams.deltatime = timeDelta
     
      physics:ComputeShadowControl(shadowParams)
    end
    
    ag3:StartMotionController()
    
    local ag3Physics = ag3:GetPhysicsObject()
    
    if(ag3Physics && ag3Physics:IsValid()) then
      ag3Physics:Wake()
    end
  end
  
end

ENT.States.AimingDirect = state
